package com.letao.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.letao.server.dto.*;
import com.letao.server.entity.*;
import com.letao.server.mapper.*;
import com.letao.server.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Service
@Slf4j
public class StatisticsServiceImpl extends ServiceImpl<StatisticsMapper, Statistics> implements IStatisticsService {
    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private OrderInfoMapper orderInfoMapper;

    @Resource
    private SpuInfoMapper spuInfoMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private ISpuService spuService;

    @Resource
    private SkuCommentInfoMapper skuCommentInfoMapper;

    @Resource
    private ISkuCommentService skuCommentService;

    @Resource
    private IUserService userService;

    @Resource
    private IBaseRegionService baseRegionService;

    @Resource
    private IOrderDetailService orderDetailService;

    @Resource
    private ISeckillService seckillService;

    @Resource
    private IOrderDetailSeckillService orderDetailSeckillService;

    @Resource
    private IOrderService orderService;

    @Override
    public Result userQuery(LocalDateTime begin, LocalDateTime end) {

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime nowDay = now.withHour(0).withMinute(0).withSecond(1);
        LocalDate nowDate = LocalDate.from(nowDay);
        List<String> sevenDate = new ArrayList<>();
        for (int i = 0; i < 21; i++) {
            sevenDate.add(nowDate.toString().substring(5));
            nowDate = nowDate.minusDays(1);
        }
        Collections.reverse(sevenDate);

        StatisticsUserDTO statisticsUserDTO = new StatisticsUserDTO();
        statisticsUserDTO.setDateList(sevenDate);

        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.select("sum(order_money) as spend,user_id as user_id");
        wrapper.between("order_status", 2, 6);
        wrapper.groupBy("user_id");
        wrapper.orderByDesc("spend");
        wrapper.last("limit 10");
        List<Map<String, Object>> maps = orderInfoMapper.selectMaps(wrapper);
        for (Map<String, Object> map : maps) {
            UserInfo userInfo = userService.getById(map.get("user_id").toString());
            map.put("account", userInfo.getAccount());
            map.put("userImage", userInfo.getUserImage());
        }

        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        List<UserInfo> userInfoList = userInfoMapper.selectList(userInfoQueryWrapper);
        statisticsUserDTO.setUserNumber(userInfoList.size());
        Collections.reverse(maps);
        statisticsUserDTO.setSpendList(maps);


        userInfoQueryWrapper.eq("sex", 0);
        statisticsUserDTO.setFemale(userInfoMapper.selectList(userInfoQueryWrapper).size());
        userInfoQueryWrapper.clear();
        userInfoQueryWrapper.eq("sex", 1);
        statisticsUserDTO.setMale(userInfoMapper.selectList(userInfoQueryWrapper).size());
        userInfoQueryWrapper.clear();
        statisticsUserDTO.setUnknownGender(statisticsUserDTO.getUserNumber() - statisticsUserDTO.getMale() - statisticsUserDTO.getFemale());

        List<Integer> dailyRegistered = new ArrayList<>();
        List<Integer> activeUserList1 = new ArrayList<>();
        Integer numberInRange = 0;

        QueryWrapper<OrderInfo> orderInfoQueryWrapper = new QueryWrapper<>();
        Map<Long, Integer> active = new HashMap<>();
        //如果时间空选就返回近七天的
        for (int i = 0; i < 21; i++) {
            Integer activeUsers = 0;
            userInfoQueryWrapper.clear();
            orderInfoQueryWrapper.clear();
            userInfoQueryWrapper.le("create_time", nowDay);
            orderInfoQueryWrapper.le("create_time", nowDay);
            nowDay = nowDay.minusDays(1);
            userInfoQueryWrapper.ge("create_time", nowDay);
            orderInfoQueryWrapper.ge("create_time", nowDay);

            HashMap<Long, Integer> activeUserMap = new HashMap<>();
            for (OrderInfo orderInfo : orderInfoMapper.selectList(orderInfoQueryWrapper)) {
                activeUserMap.put(orderInfo.getUserId(), orderInfo.getId().intValue());
                active.put(orderInfo.getUserId(), orderInfo.getId().intValue());
            }
            activeUserList1.add(activeUserMap.size());
            dailyRegistered.add(userInfoMapper.selectList(userInfoQueryWrapper).size());
            numberInRange += userInfoMapper.selectList(userInfoQueryWrapper).size();
        }
        Collections.reverse(activeUserList1);
        statisticsUserDTO.setActiveUserList(activeUserList1);
        statisticsUserDTO.setActiveUserInRange(active.size());
        statisticsUserDTO.setUserNumberInRange(numberInRange);
        Collections.reverse(dailyRegistered);

        statisticsUserDTO.setDailyRegisteredUsers(dailyRegistered);

        statisticsUserDTO.setMaxRegistered(Collections.max(dailyRegistered));
        statisticsUserDTO.setMinRegistered(Collections.min(dailyRegistered));

        return Result.success(statisticsUserDTO);
    }


    @Override
    public Result productQuery(Long oneCategoryId) {
        StatisticsProductDTO statisticsProductDTO = new StatisticsProductDTO();
        QueryWrapper<SpuInfo> spuInfoQueryWrapper = new QueryWrapper<>();
        List<SpuInfo> spuInfoList = spuInfoMapper.selectList(spuInfoQueryWrapper);
        statisticsProductDTO.setProductNumber(spuInfoList.size());

        QueryWrapper<OrderDetail> orderDetailQueryWrapper = new QueryWrapper<>();
        List<SpuDetailDTO> spuDetailSales = new ArrayList<>();

        //销量排序模块
        for (SpuInfo spuInfo : spuInfoList) {
            SpuDetailDTO spuDetailDTO = BeanUtil.copyProperties(spuInfo, SpuDetailDTO.class);
            spuDetailDTO.setSpuId(spuInfo.getId());
            Long sales = 0L;
            orderDetailQueryWrapper.eq("spu_id", spuInfo.getId());
            List<OrderDetail> orderDetails = orderDetailMapper.selectList(orderDetailQueryWrapper);
            orderDetailQueryWrapper.clear();
            for (OrderDetail orderDetail : orderDetails) {
                sales += orderDetail.getAmount();
            }
            spuDetailDTO.setSales(sales);
            spuDetailSales.add(spuDetailDTO);

        }
        spuDetailSales.sort(new Comparator<SpuDetailDTO>() {
            @Override
            public int compare(SpuDetailDTO o1, SpuDetailDTO o2) {
                if (Objects.equals(o1.getSales(), o2.getSales()))
                    return 0;
                else if (o1.getSales() > o2.getSales())
                    return -1;
                else
                    return 1;
            }
        });
        statisticsProductDTO.setSubSalesRank(spuDetailSales.subList(0, 3));
        statisticsProductDTO.setSalesRank(spuDetailSales);

        //最新上架模块
        List<SpuInfo> list = spuService.query().eq("bit", 1).orderByDesc("create_time").list();
        List<SpuInfo> returnList = new ArrayList<>();
        int size = Math.min(list.size(), 4);
        for (int i = 0; i < size; i++) {
            returnList.add(list.get(i));
        }
        statisticsProductDTO.setNewProducts(returnList);

        //好评排序模块
        List<SpuDetailDTO> spuDetailCommentDTO = new ArrayList<>();
        for (SpuInfo spuInfo : spuInfoList) {
            SpuDetailDTO spuDetailDTO = BeanUtil.copyProperties(spuInfo, SpuDetailDTO.class);
            spuDetailDTO.setSpuId(spuInfo.getId());
            Double appraise = .0;
            Long commentNum = 0L;
            List<SkuCommentInfo> skuCommentInfoList = skuCommentService.query().eq("spu_id", spuInfo.getId()).list();
            for (SkuCommentInfo skuCommentInfo : skuCommentInfoList) {
                appraise += skuCommentInfo.getAppraise();
                commentNum++;
            }
            if (commentNum != 0) {
                spuDetailDTO.setCommentNum(commentNum);
                spuDetailDTO.setAverageAppraise(Double.valueOf(new DecimalFormat("0.00").format(appraise / commentNum)));
                spuDetailCommentDTO.add(spuDetailDTO);
            }

        }
        spuDetailCommentDTO.sort(new Comparator<SpuDetailDTO>() {
            @Override
            public int compare(SpuDetailDTO o1, SpuDetailDTO o2) {
                if (Objects.equals(o1.getAverageAppraise(), o2.getAverageAppraise()))
                    return 0;
                else if (o1.getAverageAppraise() > o2.getAverageAppraise())
                    return -1;
                else
                    return 1;
            }
        });
        statisticsProductDTO.setCommentRank(spuDetailCommentDTO.subList(0, 3));


        return Result.success(statisticsProductDTO);
    }

    @Override
    public Result orderQuery(Integer sevenDays) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = now.withHour(0).withMinute(0).withSecond(1);
        LocalDateTime begin = end.minusDays(7);
        StatisticsOrderDTO statisticsOrderDTO = new StatisticsOrderDTO();
        QueryWrapper<OrderInfo> orderInfoQueryWrapper = new QueryWrapper<>();
        List<Integer> stateList = new ArrayList<>();

        if (sevenDays == 0) {
            List<OrderInfo> orderInfoList = orderInfoMapper.selectList(orderInfoQueryWrapper);
            statisticsOrderDTO.setOrderNums(orderInfoList.size());
            for (int i = 0; i < 7; i++) {
                stateList.add(orderService.query().eq("order_status", i).list().size());
            }
            statisticsOrderDTO.setOrderState(stateList);
            statisticsOrderDTO.setSeckillNums(orderService.query().eq("is_seckill", 1).list().size());
            statisticsOrderDTO.setNormalNums(statisticsOrderDTO.getOrderNums() - statisticsOrderDTO.getSeckillNums());
            Double sumMoney = .0;
            for (OrderInfo orderInfo : orderInfoList) {
                sumMoney += orderInfo.getOrderMoney();
            }
            statisticsOrderDTO.setMaxMoney(Double.valueOf(new DecimalFormat("0.00").format(sumMoney)));
        } else {
            orderInfoQueryWrapper.le("create_time", end);
            orderInfoQueryWrapper.ge("create_time", begin);
            List<OrderInfo> orderInfoList = orderInfoMapper.selectList(orderInfoQueryWrapper);
            statisticsOrderDTO.setOrderNums(orderInfoList.size());
            for (int i = 0; i < 7; i++) {

                QueryWrapper<OrderInfo> orderInfoStateQueryWrapper = new QueryWrapper<>();
                orderInfoStateQueryWrapper.le("create_time", end);
                orderInfoStateQueryWrapper.ge("create_time", begin);
                orderInfoStateQueryWrapper.eq("order_status", i);
                stateList.add(orderInfoMapper.selectList(orderInfoStateQueryWrapper).size());
                orderInfoStateQueryWrapper.clear();

            }
            statisticsOrderDTO.setOrderState(stateList);
            statisticsOrderDTO.setSeckillNums(orderService.query().eq("is_seckill", 1).list().size());
            statisticsOrderDTO.setNormalNums(statisticsOrderDTO.getOrderNums() - statisticsOrderDTO.getSeckillNums());
            Double maxMoney = .0;
            for (OrderInfo orderInfo : orderInfoList) {
                if (orderInfo.getOrderMoney() > maxMoney)
                    maxMoney = orderInfo.getOrderMoney();
            }
            statisticsOrderDTO.setMaxMoney(maxMoney);
        }

        return Result.success(statisticsOrderDTO);
    }
}
